package com.ruoyi.framework.shiro.realm;

import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.ruoyi.common.exception.jwt.JwtException;
import com.ruoyi.framework.shiro.token.JwtToken;
import com.ruoyi.framework.util.JwtUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;

public class JwtRealm extends AuthorizingRealm{
	private static final Logger logger = LoggerFactory.getLogger(JwtRealm.class);

	@Autowired
	private ISysUserService sysUserService;

	@Autowired
	private ISysMenuService menuService;

	@Autowired
	private ISysRoleService roleService;

	/**
	 * 限定这个 Realm 只处理我们自定义的 JwtToken
	 */
	@Override
	public boolean supports(AuthenticationToken token){
		return token instanceof JwtToken;
	}

	/**
	 * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可。
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException{
		String token = (String)auth.getCredentials();
		// 获取用户名
		String username = JwtUtil.getUsername(token);
		if(username == null){
			throw new JwtException("jwt.token.invalid", null);
		}
		// 用户验证
		SysUser appUser = sysUserService.selectUserByLoginName(username);
		if(appUser == null){
			throw new JwtException("jwt.user.not.exists", null);
		}
		// 验证 token
		if(!JwtUtil.verify(token, appUser.getLoginName(), JwtUtil.SECRET)){
			// 验证签名
			throw new JwtException("jwt.sign.invalid", null);
		}
		return new SimpleAuthenticationInfo(appUser, token, "jwtRealm");
	}

	/**
	 * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0){
		SysUser user = ShiroUtils.getSysUser();
		// 角色列表
		Set<String> roles = new HashSet<String>();
		// 功能列表
		Set<String> menus = new HashSet<String>();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 管理员拥有所有权限
		if(user.isAdmin()){
			info.addRole("admin");
			info.addStringPermission("*:*:*");
		}else{
			roles = roleService.selectRoleKeys(user.getUserId());
			menus = menuService.selectPermsByUserId(user.getUserId());
			// 角色加入AuthorizationInfo认证对象
			info.setRoles(roles);
			// 权限加入AuthorizationInfo认证对象
			info.setStringPermissions(menus);
		}
		return info;
	}

	/**
	 * 清理缓存权限
	 */
	public void clearCachedAuthorizationInfo(){
		this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
	}
}
